package com.yougong.api.modules.customer.service.impl;


import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.code.kaptcha.Producer;
import com.yougong.api.enums.ErrorEnum;
import com.yougong.api.modules.customer.mapper.CusRoleUserMapper;
import com.yougong.api.modules.customer.mapper.CusUserMapper;
import com.yougong.api.modules.customer.model.dto.*;
import com.yougong.api.modules.customer.model.enums.RoleEnums;
import com.yougong.api.modules.customer.model.enums.StatusEnums;
import com.yougong.api.modules.customer.model.pojo.*;
import com.yougong.api.modules.customer.model.vo.SaTokenInfoVo;
import com.yougong.api.modules.customer.service.*;

import com.yougong.api.util.CaptchaUtil;
import com.yougong.api.util.EmailUtil;
import com.yougong.common.api.CommonPage;
import com.yougong.common.api.CommonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CusUserServiceImpl extends ServiceImpl<CusUserMapper, CusUser> implements CusUserService {

    private static final Logger LOGGER = LoggerFactory.getLogger(CusUserServiceImpl.class);

    @Autowired
    private CusUserService cusUserService;


    @Autowired
    private Producer producer;

    @Autowired
    private CusCacheService cacheService;

    @Autowired
    private EmailUtil emailUtil;

    @Autowired
    private CusRoleUserMapper cusRoleUserMapper;

    @Autowired
    private CusRoleUserService cusRoleUserService;


    /**
     * 保存用户信息
     *
     * @param cusUser
     * @return
     */
    @Override
    public CommonResult saveUser(CusUser cusUser) {

        CusUser oldUser = cusUserService.getByUserNameHavePW(cusUser.getUsername());

        if (oldUser != null){
            return CommonResult.failed(ErrorEnum.INVALID_USERNAME);
        }

        //补全参数
        cusUser.setUuid(IdWorker.getIdStr());

        //验证码
        String text = producer.createText();

        try {
            String to = cusUser.getEmail();
            String title = "风起云城后台管理系统用户名及初始密码";

            String content = "您的登陆用户名：" + cusUser.getUsername() + "; 初始密码：" + text
                    + "<br>该登陆信息用于登陆风起云城后台管理系统，如非本人操作，请忽略，谢谢。";

            emailUtil.sendMessageHTML(to, title, content);
        } catch (Exception e) {
            return CommonResult.failed("发送失败");
        }

        // todo 密码加密
        String possword = SaSecureUtil.sha256(text);

        cusUser.setPassword(possword);
        //首次登录
        cusUser.setStatus(StatusEnums.COMPLETE.getType());
        cusUser.setCreateDt(LocalDateTime.now());
        cusUser.setRole(RoleEnums.ADMIN.getName());
        save(cusUser);

        return CommonResult.success(null);
    }

    /**
     * 根据手机号查询用户
     *
     * @param phonenumber
     * @return
     */
    @Override
    public CusUser getByPhonenumber(String phonenumber) {
        return getOne(Wrappers.lambdaQuery(CusUser.class).eq(CusUser::getPhonenumber,phonenumber));
    }

    /**
     * 更改用户信息
     *
     * @param userDto
     * @return
     */
    @Override
    public CommonResult updateUser(UserDto userDto) {

        //参数校验
        if (ObjectUtils.isEmpty(userDto)){
            return CommonResult.failed(ErrorEnum.REQUEST_ARGUMENTS_EMPTY);
        }

        CusUser oldUser = cusUserService.getByUserNameHavePW(userDto.getUsername());

        if (oldUser != null){
            if (!oldUser.getUuid().equals(userDto.getUuid())){
                return CommonResult.failed(ErrorEnum.INVALID_USERNAME);
            }
        }

        CusUser cusUser = cusUserService.getById(userDto.getUuid());

        BeanUtils.copyProperties(userDto,cusUser);

        updateById(cusUser);

        return CommonResult.success(null);
    }

    /**
     * 根据用户名 和 id 查找用户
     *
     * @param password
     * @param username
     * @return
     */
    @Override
    public CusUser getByUserNameAndPossword(String password, String username) {
        return getOne(Wrappers.lambdaQuery(CusUser.class).eq(CusUser::getPassword,password).eq(CusUser::getUsername,username));
    }

    @Override
    public CommonResult login(String username, String password) {

        String poss = SaSecureUtil.sha256(password);

        CusUser user = getByUserNameAndPossword(poss, username);

        if (user == null){
            return CommonResult.failed("用户名或者密码错误");
        }

        if (user.getStatus().equals(StatusEnums.FAIL.getType())){
            return CommonResult.failed(ErrorEnum.USERINFO_FREEZE);
        }

        // todo 校验登录
        StpUtil.login(user.getUuid());
        // 返回登录信息
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();

        SaTokenInfoVo saTokenInfoVo = new SaTokenInfoVo();
        BeanUtils.copyProperties(tokenInfo,saTokenInfoVo);

        //是否首次登录
        if (StatusEnums.COMPLETE.getType().equals(user.getStatus())){
            saTokenInfoVo.setType(true);
        }

        //查询该用户下的所有路由
        List<String> list = cusRoleUserMapper.getPath(user.getUuid());

        saTokenInfoVo.setPath(list);

        return CommonResult.success(saTokenInfoVo);
    }

    /**
     * 邮箱登录
     *
     * @param loginDto
     * @return
     */
    @Override
    public CommonResult emailLogin(LoginDto loginDto) {
        String poss = SaSecureUtil.sha256(loginDto.getPassword());

        CusUser user = getByUserNameAndPossword(poss, loginDto.getUsername());

        if (user == null){
            return CommonResult.failed("用户名或者密码错误");
        }

        if (user.getStatus().equals(StatusEnums.FAIL.getType())){
            return CommonResult.failed(ErrorEnum.USERINFO_FREEZE);
        }

        //验证码
        String text = producer.createText();

        try {
            String to = user.getEmail();
            String title = "风起云城后台管理系统验证码";

            String content = "验证码："+ text + "<br>该登陆信息用于登陆风起云城后台管理系统，如非本人操作，请忽略，谢谢。";

            //存入缓存
            cacheService.setCache(new CaptchaDTO(loginDto.getCaptchaId(),text));
            emailUtil.sendMessageHTML(to, title, content);
        } catch (Exception e) {
            return CommonResult.failed("发送失败");
        }

        return CommonResult.success(null);
    }


    /**
     * 条件查询所有用户
     * @param userListDto
     * @return
     */
    @Override
    public CommonResult getCusUserList(UserListDto userListDto) {
        //分页条件
        Page<CusUser> page = new Page<>(userListDto.getCurrent(),userListDto.getPageSize());

        //查询条件
        LambdaQueryWrapper<CusUser> eq = Wrappers.lambdaQuery(CusUser.class)
                .isNull(CusUser::getRole)
                .like(!StringUtils.isEmpty(userListDto.getUsername()), CusUser::getUsername, userListDto.getUsername())
                .eq(!StringUtils.isEmpty(userListDto.getStatus()), CusUser::getStatus, userListDto.getStatus())
                .eq(!StringUtils.isEmpty(userListDto.getRole()), CusUser::getRole, userListDto.getRole())
                .like(!StringUtils.isEmpty(userListDto.getPhonenumber()),CusUser::getPhonenumber,userListDto.getPhonenumber())
                .like(!StringUtils.isEmpty(userListDto.getEmail()),CusUser::getEmail,userListDto.getEmail())
                .orderByDesc(CusUser::getCreateDt);

        if (!ObjectUtils.isEmpty(userListDto.getCreateDt()) && userListDto.getCreateDt().size() == 2){
            eq.between(CusUser::getCreateDt,userListDto.getCreateDt().get(0)
                    ,userListDto.getCreateDt().get(1));
        }

        page(page,eq);

        CommonPage<CusUser> cusUserCommonPage = new CommonPage<>();

        cusUserCommonPage.setList(page.getRecords());
        cusUserCommonPage.setPageSize(userListDto.getPageSize());
        cusUserCommonPage.setCurrent((int) page.getPages());
        cusUserCommonPage.setTotal(page.getTotal());

        return CommonResult.success(cusUserCommonPage);
    }

    /**
     * 修改密码
     * @param passWordDto
     * @return
     */
    @Override
    public CommonResult updatePassword(PassWordDto passWordDto) {

        //查询用户
        CusUser user = cusUserService.getById(passWordDto.getUuid());

        if (user == null){
            return CommonResult.failed(ErrorEnum.NOT_USER);
        }

        //加秘
        String poss = SaSecureUtil.sha256(passWordDto.getPassword());

        //修改状态
        if (user.getStatus().equals(StatusEnums.COMPLETE.getType())){
            user.setStatus(StatusEnums.SUCCESS.getType());
        }

        user.setPassword(poss);

        cusUserService.updateById(user);

        return CommonResult.success(null);
    }

    /**
     * 批量修改用户状态
     *
     * @param statusDtoList
     * @return
     */
    @Override
    public CommonResult updateStatus(List<StatusDto> statusDtoList) {

        List<CusUser> userList = statusDtoList.stream().map(statusDto -> {
            CusUser cusUser = new CusUser();

            cusUser.setUuid(statusDto.getId());
            cusUser.setStatus(statusDto.getStatus());

            if (statusDto.getStatus().equals(StatusEnums.FAIL.getType())){
                StpUtil.logout(cusUser.getUuid());
            }

            return cusUser;
        }).collect(Collectors.toList());

        updateBatchById(userList);

        return CommonResult.success(null);
    }

    @Override
    public ResponseEntity<byte[]> getVerificationCode(String captchaId) throws IOException {
        //生成文字验证码
        //String random = producer.createText();
        String random = CaptchaUtil.random();
        //生成图片验证码
        BufferedImage image = producer.createImage(random);
        //BufferedImage image = CaptchaUtil.outputImage(random);
        //保存到 session 目前session无法使用 需前端 withCredentials: true
        //保存到缓存中ehcache 或 redis
        cacheService.setCache(new CaptchaDTO(captchaId,CaptchaUtil.result));
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageIO.write(image, "jpg", out);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cache-Control", "no-store, no-cache");
        headers.add("Content-Type", "image/jpeg");
        return new ResponseEntity<byte[]>(out.toByteArray(), headers, HttpStatus.CREATED);
    }

    @Override
    public CommonResult getEmailCode(EmailCodeDto emailCodeDto) {

        //根据用户名和邮箱查询用户
        CusUser cusUser =cusUserService.getByUserNameHavePW(emailCodeDto.getUsername());

        if (cusUser == null){
            return CommonResult.failed(ErrorEnum.NOT_USER_EMAIL);
        }

        //验证码
        String text = producer.createText();

        try {
            String to = cusUser.getEmail();
            String title = "风起云城后台管理系统验证码";

            String content = "验证码："+ text + "<br>该验证码用于重置风起云城后台管理系统密码，如非本人操作，请忽略，谢谢。";

            //存入缓存
            cacheService.setCache(new CaptchaDTO(emailCodeDto.getCaptchaId(),text));
            emailUtil.sendMessageHTML(to, title, content);
        } catch (Exception e) {
            return CommonResult.failed("发送失败");
        }

        return CommonResult.success(null);
    }

    @Override
    public CommonResult resetPassword(EmailCodeDto emailCodeDto) {

        CaptchaDTO cache = cacheService.getCache(emailCodeDto.getCaptchaId());

        //删除缓存
        cacheService.delCache(emailCodeDto.getCaptchaId());

        if (cache == null || !cache.getCaptchaValue().equals(emailCodeDto.getCode())){
            return CommonResult.failed(ErrorEnum.REQUEST_PC_LOGIN_CODE_ERROR);
        }

        //重置密码
        CusUser user = getByUserNameHavePW(emailCodeDto.getUsername());

        if (user == null){
            return CommonResult.failed(ErrorEnum.REQUEST_ARGUMENTS_ERROR);
        }

        //验证码
        String text = producer.createText() + producer.createText();

        try {
            String to = user.getEmail();
            String title = "风起云城后台管理系统验证码";

            String content = "重置密码："+ text + "<br>该密码用于登录风起云城后台管理系统，如非本人操作，请忽略，谢谢。";

            emailUtil.sendMessageHTML(to, title, content);
        } catch (Exception e) {
            return CommonResult.failed("发送失败");
        }

        String poss = SaSecureUtil.sha256(text);
        user.setPassword(poss);

        cusUserService.updateById(user);

        return CommonResult.success(null);
    }

    @Override
    public CusUser getByEmailAndUserName(String userName, String email) {

        List<CusUser> cusUserList = list(Wrappers.lambdaQuery(CusUser.class).eq(CusUser::getUsername, userName)
                .eq(CusUser::getEmail, email));

        for (CusUser cusUser : cusUserList) {
            if (cusUser.getOpenId() == null){
                return cusUser;
            }
        }

        return null;
    }

    /**
     * 校验验证码 发送邮箱验证码
     *
     * @param emailDto
     * @return
     */
    @Override
    public CommonResult checkVerificationCode(EmailDto emailDto) {

        //判断是否存在该邮箱
        Boolean b = cusUserService.getByEmail(emailDto.getEmail());


        if (!b){
            return CommonResult.failed(ErrorEnum.NOT_EMAIL);
        }

        //验证码
        String text = producer.createText();

        try {
            String to = emailDto.getEmail();
            String title = "风起云城后台管理";

            String content = "您的验证码为"+ text;

            //存入缓存
            cacheService.setCache(new CaptchaDTO(emailDto.getEmailId(),text));
            emailUtil.sendMessageHTML(to, title, content);
        } catch (Exception e) {
            return CommonResult.failed("发送失败");
        }

        return CommonResult.success(null);
    }

    /**
     * 根据用户名查询 但是无密码
     *
     * @param username
     * @return
     */
    @Override
    public CusUser getByUserNameHavePW(String username) {
        return getOne(Wrappers.lambdaQuery(CusUser.class).eq(CusUser::getUsername,username).isNotNull(CusUser::getPassword));
    }

    /**
     * 判断是否存在该邮箱
     *
     * @param email
     * @return
     */
    @Override
    public Boolean getByEmail(String email) {

        Boolean b = false;

        List<CusUser> list = list(Wrappers.lambdaQuery(CusUser.class).eq(CusUser::getEmail, email));

        if (!ObjectUtils.isEmpty(list)){
            b = true;
        }

        return b;
    }


}
